#include "onvif_server_impl.h"

#include <algorithm>

namespace {
constexpr const char *kDefaultAdminUser = "admin";
constexpr const char *kDefaultAdminPassword = "admin";
constexpr const char *kDefaultProfileToken = "profile_1";
constexpr const char *kDefaultProfileName = "DefaultProfile";
} // namespace

namespace El {
namespace Onvif {

OnvifServerImpl::OnvifServerImpl(int port)
    : onvifPort_(port),
      isRunning_(false),
      wsDiscoveryEnabled_(true),
      securityMode_(SecurityMode::NONE),
      deviceInfo_(CreateDefaultDeviceInformation()),
      networkConfig_(CreateDefaultNetworkConfiguration()),
      serviceCapabilities_(CreateDefaultCapabilities())
{
    User admin;
    admin.username = kDefaultAdminUser;
    admin.password = kDefaultAdminPassword;
    admin.userLevel = User::UserLevel::ADMINISTRATOR;

    users_.push_back(admin);

    MediaProfile profile;
    profile.token = kDefaultProfileToken;
    profile.name = kDefaultProfileName;
    profile.fixed = true;
    profile.videoSourceToken = "video_source_1";
    profile.videoEncoderToken = "video_encoder_1";
    profile.streamUris.rtspUri = "rtsp://127.0.0.1:554/stream1";
    profile.streamUris.hlsUri = "http://127.0.0.1:8080/hls/stream.m3u8";
    profile.streamUris.rtmpUri = "rtmp://127.0.0.1/live/stream";

    mediaProfiles_.push_back(profile);
}

bool OnvifServerImpl::Start()
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    if (isRunning_) {
        return true;
    }

    isRunning_ = true;
    return true;
}

void OnvifServerImpl::Stop()
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    isRunning_ = false;
}

bool OnvifServerImpl::IsRunning() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return isRunning_;
}

void OnvifServerImpl::SetDeviceInformation(const DeviceInformation &deviceInfo)
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    deviceInfo_ = deviceInfo;
}

DeviceInformation OnvifServerImpl::GetDeviceInformation() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return deviceInfo_;
}

void OnvifServerImpl::SetNetworkConfiguration(const NetworkInterface &networkConfig)
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    networkConfig_ = networkConfig;
}

NetworkInterface OnvifServerImpl::GetNetworkConfiguration() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return networkConfig_;
}

void OnvifServerImpl::SetOnvifPort(int port)
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    onvifPort_ = port;
}

int OnvifServerImpl::GetOnvifPort() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return onvifPort_;
}

void OnvifServerImpl::EnableWSDiscovery(bool enable)
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    wsDiscoveryEnabled_ = enable;
}

bool OnvifServerImpl::IsWSDiscoveryEnabled() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return wsDiscoveryEnabled_;
}

void OnvifServerImpl::SetSecurityMode(SecurityMode mode)
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    securityMode_ = mode;
}

SecurityMode OnvifServerImpl::GetSecurityMode() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return securityMode_;
}

bool OnvifServerImpl::AddUser(const User &user)
{
    std::lock_guard<std::mutex> lock(userMutex_);

    if (users_.size() >= kDefaultMaxUsers) {
        return false;
    }

    auto existIt = std::find_if(users_.begin(), users_.end(),
                                [&user](const User &item) { return item.username == user.username; });

    if (existIt != users_.end()) {
        return false;
    }

    users_.push_back(user);
    return true;
}

bool OnvifServerImpl::RemoveUser(const std::string &username)
{
    std::lock_guard<std::mutex> lock(userMutex_);

    auto it =
        std::find_if(users_.begin(), users_.end(), [&username](const User &item) { return item.username == username; });

    if (it == users_.end()) {
        return false;
    }

    users_.erase(it);
    return true;
}

std::vector<User> OnvifServerImpl::GetUsers() const
{
    std::lock_guard<std::mutex> lock(userMutex_);
    return users_;
}

bool OnvifServerImpl::AddMediaProfile(const MediaProfile &profile)
{
    std::lock_guard<std::mutex> lock(profileMutex_);

    if (mediaProfiles_.size() >= kDefaultMaxProfiles) {
        return false;
    }

    auto existIt = std::find_if(mediaProfiles_.begin(), mediaProfiles_.end(),
                                [&profile](const MediaProfile &item) { return item.token == profile.token; });

    if (existIt != mediaProfiles_.end()) {
        return false;
    }

    mediaProfiles_.push_back(profile);
    return true;
}

bool OnvifServerImpl::RemoveMediaProfile(const std::string &token)
{
    std::lock_guard<std::mutex> lock(profileMutex_);

    auto it = std::find_if(mediaProfiles_.begin(), mediaProfiles_.end(),
                           [&token](const MediaProfile &item) { return item.token == token; });

    if (it == mediaProfiles_.end()) {
        return false;
    }

    mediaProfiles_.erase(it);
    return true;
}

std::vector<MediaProfile> OnvifServerImpl::GetMediaProfiles() const
{
    std::lock_guard<std::mutex> lock(profileMutex_);
    return mediaProfiles_;
}

ServiceCapabilities OnvifServerImpl::GetServiceCapabilities() const
{
    std::lock_guard<std::mutex> lock(stateMutex_);
    return serviceCapabilities_;
}

ServiceCapabilities OnvifServerImpl::CreateDefaultCapabilities()
{
    ServiceCapabilities capabilities;
    capabilities.device.io = false;
    capabilities.device.security = false;
    capabilities.device.systemBackup = false;
    capabilities.device.systemLogging = false;
    capabilities.device.firmwareUpgrade = false;
    capabilities.device.maxUsers = static_cast<int>(kDefaultMaxUsers);

    capabilities.media.videoSources = true;
    capabilities.media.audioSources = false;
    capabilities.media.rtpMulticast = false;
    capabilities.media.rotation = false;
    capabilities.media.videoSourceMode = false;
    capabilities.media.osd = false;
    capabilities.media.exiCompression = false;
    capabilities.media.maxProfiles = static_cast<int>(kDefaultMaxProfiles);

    capabilities.ptz.eFlip = false;
    capabilities.ptz.reverse = false;
    capabilities.ptz.getCompatibleConfiguration = false;
    capabilities.ptz.moveStatus = false;
    capabilities.ptz.statusPosition = false;

    return capabilities;
}

DeviceInformation OnvifServerImpl::CreateDefaultDeviceInformation()
{
    DeviceInformation info;
    info.manufacturer = "endless";
    info.model = "onvif-device";
    info.firmwareVersion = "0.1.0";
    info.serialNumber = "000000000000";
    info.hardwareId = "onvif-simulated";
    return info;
}

NetworkInterface OnvifServerImpl::CreateDefaultNetworkConfiguration()
{
    NetworkInterface network;
    network.token = "eth0";
    network.enabled = true;
    network.dhcp = true;
    network.ipAddress = "192.168.1.100";
    network.prefixLength = 24;
    network.gateway = "192.168.1.1";
    network.dns = {"8.8.8.8", "8.8.4.4"};
    network.macAddress = "00:11:22:33:44:55";
    network.mtu = 1500;
    return network;
}

} // namespace Onvif
} // namespace El
